package zd

import (
	"context"
	"strings"

	_ "gitee.com/chunanyong/dm"
	"gitee.com/chunanyong/zorm"
	_ "github.com/lib/pq"
)

type CtxKey string

// const DM DialectType = "DM"
const PG CtxKey = "postgresql"
const ORACLE CtxKey = "oracle"
const DM CtxKey = "DM"
const Schema CtxKey = "schemaName"

// InitDao InitDaoDM 初始化数据库
//
// 注册自定义类型: RegEnumByteType RegBoolType(dm.BIT) RegNumberType(dm.NUMBER,dm.NUMERIC)
//
//	@param dao 参见: Go数据库驱动列表:https://github.com/golang/go/wiki/SQLDrivers
//	@return context.Context 数据层上下文
//	@return error 错误
func InitDao(dao zorm.DataSourceConfig, schemaName string) (context.Context, error) {
	// 根据dbDaoConfig创建dbDao, 一个数据库只执行一次,第一个执行的数据库为 defaultDao,后续zorm.xxx方法,默认使用的就是defaultDao
	dbDao, err := zorm.NewDBDao(&dao)
	if err != nil {
		return nil, err
	}
	var ctx = context.Background()
	if dao.Dialect == "postgresql" { // ctx 中标注为 postgresql
		ctx = context.WithValue(ctx, PG, true)
		ctx = context.WithValue(ctx, Schema, toSnakeString(schemaName))
	} else {
		if dao.Dialect == "oracle" {
			ctx = context.WithValue(ctx, ORACLE, true)
		} else if dao.Dialect == "dm" {
			ctx = context.WithValue(ctx, DM, true)
		}
		ctx = context.WithValue(ctx, Schema, strings.ToUpper(schemaName))
	}
	RegNumberType()
	RegBoolType()
	RegEnumByteType()
	return dbDao.BindContextDBConnection(ctx)
}

// DisableTransaction 关闭事务
//
//	@param ctx 上下文
//	@return context.Context 返回新的上下文
func DisableTransaction(ctx context.Context) context.Context {
	ctx, _ = zorm.BindContextDisableTransaction(ctx)
	return ctx
}

// InitDaoDM 初始化数据库
//
// 注册自定义类型: RegEnumByteType RegBoolType(dm.BIT) RegNumberType(dm.NUMBER,dm.NUMERIC)
//
//	@param dmDSN string dm://SYSDBA:SYSDBA001@localhost:5236
//	@return context.Context 数据层上下文
//	@return error 错误
func InitDaoDM(dmDSN, schemaName string) (context.Context, error) {
	//自定义zorm日志输出
	//zorm.LogCallDepth = 4 //日志调用的层级
	//zorm.FuncLogError = myFuncLogError //记录异常日志的函数
	//zorm.FuncLogPanic = myFuncLogPanic //记录panic日志,默认使用defaultLogError实现
	//zorm.FuncPrintSQL = myFuncPrintSQL //打印sql的函数

	//自定义日志输出格式,把FuncPrintSQL函数重新赋值
	//log.SetFlags(log.LstdFlags)
	//zorm.FuncPrintSQL = zorm.FuncPrintSQL

	//自定义主键生成
	//zorm.FuncGenerateStringID=funcmyId

	//Go数据库驱动列表:https://github.com/golang/go/wiki/SQLDrivers

	//dbDaoConfig 数据库的配置.这里只是模拟,生产应该是读取配置配置文件,构造DataSourceConfig
	dbDaoConfig := zorm.DataSourceConfig{
		//DSN 数据库的连接字符串,parseTime=true会自动转换为time格式,默认查询出来的是[]byte数组
		// DSN: "root:root@tcp(127.0.0.1:3306)/readygo?charset=utf8&parseTime=true",
		DSN: dmDSN,
		//DriverName 数据库驱动名称:mysql,postgres,oci8,sqlserver,sqlite3,go_ibm_db,clickhouse,dm,kingbase,aci,taosSql|taosRestful 和Dialect对应
		DriverName: "dm",
		//Dialect 数据库方言:mysql,postgresql,oracle,mssql,sqlite,db2,clickhouse,dm,kingbase,shentong,tdengine 和 DriverName 对应
		Dialect: "dm",
		//MaxOpenConns 数据库最大连接数 默认50
		MaxOpenConns: 50,
		//MaxIdleConns 数据库最大空闲连接数 默认50
		MaxIdleConns: 50,
		//ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		ConnMaxLifetimeSecond: 600,
		//SlowSQLMillis 慢sql的时间阈值,单位毫秒.小于0是禁用SQL语句输出;等于0是只输出SQL语句,不计算执行时间;大于0是计算SQL执行时间,并且>=SlowSQLMillis值
		SlowSQLMillis: 0,
		//DefaultTxOptions 事务隔离级别的默认配置,默认为nil
		//DefaultTxOptions: nil,
		//如果是使用分布式事务,建议使用默认配置
		//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},

		//FuncGlobalTransaction seata/hptx全局分布式事务的适配函数,返回IGlobalTransaction接口的实现
		//业务必须调用 ctx,_=zorm.BindContextEnableGlobalTransaction(ctx) 开启全局分布事务
		//FuncGlobalTransaction : MyFuncGlobalTransaction,

		//SQLDB 使用现有的数据库连接,优先级高于DSN
		//SQLDB : nil,

		//DisableTransaction 禁用事务,默认false,如果设置了DisableTransaction=true,Transaction方法失效,不再要求有事务,为了处理某些数据库不支持事务,比如TDengine
		//禁用事务应该有驱动伪造事务API,不应该有orm实现,clickhouse的驱动就是这样做的
		// DisableTransaction: true, // 禁用全局事务
	}

	return InitDao(dbDaoConfig, schemaName)
}

// InitDaoOracle 初始化 oracle
//
// 应用需要 import _ "github.com/godror/godror"
//
// Go数据库驱动列表:https://github.com/golang/go/wiki/SQLDrivers
//
//	@param crmsDSN string
//	@return context.Context 数据上下文
//	@return error 错误
func InitDaoOracle(oraDSN, schemaName string) (context.Context, error) {
	dbDaoConfig := zorm.DataSourceConfig{
		DSN: oraDSN,
		//DriverName 数据库驱动名称:mysql,postgres,oci8,sqlserver,sqlite3,go_ibm_db,clickhouse,dm,kingbase,aci,taosSql|taosRestful 和Dialect对应
		DriverName: "godror",
		//Dialect 数据库方言:mysql,postgresql,oracle,mssql,sqlite,db2,clickhouse,dm,kingbase,shentong,tdengine 和 DriverName 对应
		Dialect: "oracle",
		//MaxOpenConns 数据库最大连接数 默认50
		MaxOpenConns: 50,
		//MaxIdleConns 数据库最大空闲连接数 默认50
		MaxIdleConns: 50,
		//ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		ConnMaxLifetimeSecond: 600,
		//SlowSQLMillis 慢sql的时间阈值,单位毫秒.小于0是禁用SQL语句输出;等于0是只输出SQL语句,不计算执行时间;大于0是计算SQL执行时间,并且>=SlowSQLMillis值
		SlowSQLMillis: 0,
		//DefaultTxOptions 事务隔离级别的默认配置,默认为nil
		//DefaultTxOptions: nil,
		//如果是使用分布式事务,建议使用默认配置
		//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},

		//FuncGlobalTransaction seata/hptx全局分布式事务的适配函数,返回IGlobalTransaction接口的实现
		//业务必须调用 ctx,_=zorm.BindContextEnableGlobalTransaction(ctx) 开启全局分布事务
		//FuncGlobalTransaction : MyFuncGlobalTransaction,

		//SQLDB 使用现有的数据库连接,优先级高于DSN
		//SQLDB : nil,

		//DisableTransaction 禁用事务,默认false,如果设置了DisableTransaction=true,Transaction方法失效,不再要求有事务,为了处理某些数据库不支持事务,比如TDengine
		//禁用事务应该有驱动伪造事务API,不应该有orm实现,clickhouse的驱动就是这样做的
		// DisableTransaction: true, // 禁用全局事务
	}

	return InitDao(dbDaoConfig, schemaName)
}

// InitDaoOracle 初始化 oracle
//
// 应用需要 import _ "github.com/godror/godror"
//
// Go数据库驱动列表:https://github.com/golang/go/wiki/SQLDrivers
//
//	@param crmsDSN string
//	@return context.Context 数据上下文
//	@return error 错误
func InitDaoPostgres(pgDSN, schemaName string) (context.Context, error) {
	dbDaoConfig := zorm.DataSourceConfig{
		DSN: pgDSN,
		//DriverName 数据库驱动名称:mysql,postgres,oci8,sqlserver,sqlite3,go_ibm_db,clickhouse,dm,kingbase,aci,taosSql|taosRestful 和Dialect对应
		DriverName: "postgres",
		//Dialect 数据库方言:mysql,postgresql,oracle,mssql,sqlite,db2,clickhouse,dm,kingbase,shentong,tdengine 和 DriverName 对应
		Dialect: "postgresql",
		//MaxOpenConns 数据库最大连接数 默认50
		MaxOpenConns: 50,
		//MaxIdleConns 数据库最大空闲连接数 默认50
		MaxIdleConns: 50,
		//ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		ConnMaxLifetimeSecond: 600,
		//SlowSQLMillis 慢sql的时间阈值,单位毫秒.小于0是禁用SQL语句输出;等于0是只输出SQL语句,不计算执行时间;大于0是计算SQL执行时间,并且>=SlowSQLMillis值
		SlowSQLMillis: 0,
		//DefaultTxOptions 事务隔离级别的默认配置,默认为nil
		//DefaultTxOptions: nil,
		//如果是使用分布式事务,建议使用默认配置
		//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},

		//FuncGlobalTransaction seata/hptx全局分布式事务的适配函数,返回IGlobalTransaction接口的实现
		//业务必须调用 ctx,_=zorm.BindContextEnableGlobalTransaction(ctx) 开启全局分布事务
		//FuncGlobalTransaction : MyFuncGlobalTransaction,

		//SQLDB 使用现有的数据库连接,优先级高于DSN
		//SQLDB : nil,

		//DisableTransaction 禁用事务,默认false,如果设置了DisableTransaction=true,Transaction方法失效,不再要求有事务,为了处理某些数据库不支持事务,比如TDengine
		//禁用事务应该有驱动伪造事务API,不应该有orm实现,clickhouse的驱动就是这样做的
		// DisableTransaction: true, // 禁用全局事务
	}

	return InitDao(dbDaoConfig, schemaName)
}
